﻿using UnityEngine;
using System.Collections.Generic;
#if UNITY_EDITOR
using UnityEditor;
#endif

[System.Serializable]
public class CharacterInfo : InteractiveInfo
{
	[Header("Character")]
	public StatBody body = new StatBody();
	
	public StatData strength = new StatData();
	public StatData precision = new StatData();
	public StatData defense = new StatData();
	
	public StatData initiative = new StatData();
	public StatData speed = new StatData();

	public UseableInfo baseWeapon = null;
	public List<UseableInfo> equipped = new List<UseableInfo>();
	public List<InteractiveInfo> contents = new List<InteractiveInfo>();

	public void AddContent(InteractiveInfo _info)
	{
		if (equipped.Contains(_info as UseableInfo) || contents.Contains(_info))
		{
			Debug.LogError("Item was already in lists equipped or contents");
		}

		contents.Add(_info);
	}

	public bool DropItem(InteractiveInfo _info)
	{
		foreach (InteractiveInfo info in contents)
		{
			if (info == _info)
			{
				contents.Remove(_info);
				return true;
			}
		}

		foreach (UseableInfo info in equipped)
		{
			if (info == _info)
			{
				equipped.Remove(_info as UseableInfo);
				return true;
			}
		}

		return false;
	}

	public void SwitchEquipped(UseableInfo _info)
	{
		if (_info is UseableInfo)
		{
			if (equipped.Contains(_info))
			{
				equipped.Remove(_info);
				contents.Add(_info);
			}
			else
			{
				contents.Remove(_info);
				equipped.Add(_info);
			}
		}
		else
		{
			Debug.LogError("Interactive " + _info + " can't be equipped");
		}
	}

	public bool HasWeapon()
	{
		foreach (UseableInfo info in equipped)
		{
			foreach (StatBonus bonus in info.bonus)
			{
				if (bonus.statType == StatType.Strength)
				{
					return true;
				}
			}
		}

		return false;
	}

	private StatData EquippedStat(StatType _type)
	{
		return TotalStat(_type, new StatData());
	}

	private StatData TotalStat(StatType _type)
	{
		return TotalStat(_type, GetStat(_type));
	}

	private StatData TotalStat(StatType _type, StatData _data)
	{
		StatData data = _data;
		foreach (UseableInfo info in equipped)
		{
			foreach (StatBonus bonus in info.bonus)
			{
				if (bonus.statType == _type)
				{
					data += bonus;
				}
			}
		}
		
		return data;
	}

	public void BeAttacked(CharacterInfo _attacker, BodyType _bodyPart)
	{
		float equippedPrecision = _attacker.EquippedStat(StatType.Precision).GetRandomValue();
		float randomStrength = _attacker.TotalStat(StatType.Strength).GetRandomValue();
		float[] damages = StatBody.CalculateDamage(_bodyPart, equippedPrecision, randomStrength);
		body.ApplyDamage(damages);
	}

	public StatData GetStat(StatType _type)
	{
		switch (_type)
		{
		case StatType.Strength:
			return strength;
			
		case StatType.Precision:
			return precision;
			
		case StatType.Defense:
			return defense;
			
		case StatType.Initiative:
			return initiative;
			
		case StatType.Speed:
			return speed;
		}

		Debug.LogError("StatType is not supported by CharacterInfo");
		return null;
	}

	public string GetStatString(StatType _type)
	{
		switch (_type)
		{
		case StatType.Strength:
			return strength.GetAverageValue().ToString();

		case StatType.Precision:
			return precision.GetAverageValue().ToString();

		case StatType.Defense:
			return defense.GetAverageValue().ToString();

		case StatType.Initiative:
			return initiative.GetAverageValue().ToString();

		case StatType.Speed:
			return speed.GetAverageValue().ToString();
		}
		
		Debug.LogError("StatType is not supported by CharacterInfo");
		return "Error : " + _type.ToString();
	}
	
	public override string[] GetStrings()
	{
		string[] stats = new string[6];
		
		stats[0] = "Head : " + body.GetStat(BodyType.Head).GetDisplayString();
		stats[1] = "L-Arm : " + body.GetStat(BodyType.L_Arm).GetDisplayString();
		stats[2] = "R-Arm : " + body.GetStat(BodyType.R_Arm).GetDisplayString();
		stats[3] = "Torso : " + body.GetStat(BodyType.Torso).GetDisplayString();
		stats[4] = "L-Leg : " + body.GetStat(BodyType.L_Leg).GetDisplayString();
		stats[5] = "R-Leg : " + body.GetStat(BodyType.R_Leg).GetDisplayString();

		return stats;
	}
	
	public override InteractiveInfo Clone()
	{
		return CloneCharacter<CharacterInfo>();
	}
	
	public T CloneCharacter<T>() where T : CharacterInfo
	{
		T info = base.CloneInteractive<T>();
		
		info.baseWeapon = baseWeapon;
		info.body.SetStat(BodyType.Head, body.GetStat(BodyType.Head).Clone());
		info.body.SetStat(BodyType.L_Arm, body.GetStat(BodyType.L_Arm).Clone());
		info.body.SetStat(BodyType.R_Arm, body.GetStat(BodyType.R_Arm).Clone());
		info.body.SetStat(BodyType.Torso, body.GetStat(BodyType.Torso).Clone());
		info.body.SetStat(BodyType.L_Leg, body.GetStat(BodyType.L_Leg).Clone());
		info.body.SetStat(BodyType.R_Leg, body.GetStat(BodyType.R_Leg).Clone());
		info.strength = strength.Clone();
		info.precision = precision.Clone();
		info.defense = defense.Clone();
		info.initiative = initiative.Clone();
		info.speed = speed.Clone();
		info.equipped = equipped;
		info.contents = contents;
		return info;
	}
	
	#region Editor
#if UNITY_EDITOR
	// Return true id it is to be removed
	public override DrawResult DrawEditor()
	{
		DrawResult result = base.DrawEditor();
		if (result != DrawResult.None)
		{
			return result;
		}

		baseWeapon = (UseableInfo)EditorGUILayout.ObjectField("Base Weapon", baseWeapon, typeof(UseableInfo), false);
		
		EditorGUILayout.BeginHorizontal();
		{
			EditorGUILayout.BeginVertical();
			{
				body.GetStat(BodyType.Head).Draw("Head", true, "/");
				body.GetStat(BodyType.L_Arm).Draw("L-Arm", true, "/");
				body.GetStat(BodyType.R_Arm).Draw("R-Arm", true, "/");
				body.GetStat(BodyType.Torso).Draw("Torso", true, "/");
				body.GetStat(BodyType.L_Leg).Draw("L-Leg", true, "/");
				body.GetStat(BodyType.R_Leg).Draw("R-Leg", true, "/");
			}
			EditorGUILayout.EndVertical();
			EditorGUILayout.BeginVertical();
			{
				strength.Draw("Strength", true, "-");
				precision.Draw("Precision", true, "-");
				defense.Draw("Defense", true, "-");
				initiative.Draw("Initiative", false);
				speed.Draw("Speed", false);
			}
			EditorGUILayout.EndVertical();
		}
		EditorGUILayout.EndHorizontal();

		ContainerInfo.DrawContents(contents);
		
		return DrawResult.None;
	}
#endif
	#endregion
}